import React, { useState, useRef } from 'react';
import {
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions,
  Button,
  TextField,
  Box,
  InputAdornment,
  styled,
} from '@mui/material';
import { Folder as FolderIcon } from '@mui/icons-material';
import FileBrowser from '../../general/FileBrowser';
import Tooltip from '../../general/Tooltip';

const ACCEPTED_EXTENSIONS = '.py .zip .gz .tar.gz .pdf .txt .xls .png .jpeg .json';

const StyledRoot = styled(Box)(({ theme }) => ({
  color: theme.palette.common.white,
}));

const StyledContainer = styled(Box)(({ theme }) => ({
  marginTop: theme.spacing(2),
  display: 'flex',
  flexDirection: 'row',
  alignItems: 'flex-end',
  width: '100%',
}));

const StyledIcon = styled(Box)(({ theme }) => ({
  '&:hover': {
    backgroundColor: 'inherit',
  },
  flex: '0 0 4%',
  marginRight: theme.spacing(2),
  width: theme.typography.h3.fontSize,
  height: theme.typography.h3.fontSize,
  padding: '0px !important',
  zIndex: theme.zIndex.modal,
  cursor: 'pointer',
}));

interface UploadDownloadFilesDialogProps {
  open?: boolean;
  mode?: 'UPLOAD' | 'DOWNLOAD';
  onRequestClose?: () => void;
  openSnackBar?: (message: string) => void;
  [key: string]: any;
}

/**
 * UploadDownloadFilesDialog Component
 * Dialog for uploading or downloading files from/to the server
 */
const UploadDownloadFilesDialog: React.FC<UploadDownloadFilesDialogProps> = ({
  open = true,
  mode = 'UPLOAD',
  onRequestClose,
  openSnackBar,
  ...otherProps
}) => {
  const [uploadFiles, setUploadFiles] = useState<FileList | null>(null);
  const [downloadPaths, setDownloadPaths] = useState<string[]>([]);
  const [downloadPathsDisplayText, setDownloadPathsDisplayText] = useState('');
  const [explorerDialogOpen, setExplorerDialogOpen] = useState(false);
  const [filterFiles, setFilterFiles] = useState<string>('');
  const fileInputRef = useRef<HTMLInputElement>(null);
  const messageRef = useRef<string>('');

  const onUploadFileArrayChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
    const { files } = event.target;
    if (files && files.length > 0) {
      // Validation would go here (maxSelectFile, checkMimeType, checkFileSize)
      setUploadFiles(files);
    }
  };

  const uploadFilesHandler = async (): Promise<void> => {
    if (!uploadFiles || uploadFiles.length === 0) {
      return;
    }

    const formData = new FormData();
    for (let i = 0; i < uploadFiles.length; i++) {
      formData.append('file', uploadFiles.item(i)!);
    }

    // Show spinner if GEPPETTO is available
    if ((window as any).GEPPETTO) {
      (window as any).GEPPETTO.trigger((window as any).GEPPETTO.Events.Show_spinner, 'UPLOADING FILES');
    }

    try {
      const response = await fetch('uploads', {
        method: 'POST',
        body: formData,
      });
      if (response.status === 200) {
        messageRef.current = response.statusText;
      } else {
        messageRef.current = 'No file uploaded.';
        console.warn(
          `Response error uploading files. Status code ${response.status}. Message ${response.statusText}`,
        );
      }
    } catch (error) {
      messageRef.current = 'Server error. Please try again.';
      console.warn(error);
    } finally {
      if ((window as any).GEPPETTO) {
        (window as any).GEPPETTO.trigger((window as any).GEPPETTO.Events.Hide_spinner);
      }
      if (openSnackBar) {
        openSnackBar(messageRef.current);
      }
      if (onRequestClose) {
        onRequestClose();
      }
    }
  };

  const generateUrl = (): { url: string; downloadFileName: string } => {
    let url = 'downloads';
    let downloadFileName = 'download.tar.gz';

    if (downloadPaths.length > 0) {
      downloadPaths.forEach((path, index) => {
        url += `${index === 0 ? '?' : '&'}uri=${path}`;
      });
      if (downloadPaths.length === 1) {
        downloadFileName = downloadPaths[0].split('/').pop() || 'download.tar.gz';
      }
    } else if (downloadPathsDisplayText) {
      url += `?uri=${downloadPathsDisplayText}`;
    } else {
      url = '';
      downloadFileName = '';
    }
    return { url, downloadFileName };
  };

  const downloadBlob = (blob: Blob, fileName: string): void => {
    const url = window.URL.createObjectURL(new Blob([blob]));
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', fileName);
    document.body.appendChild(link);
    link.click();
    link.parentNode?.removeChild(link);
    window.URL.revokeObjectURL(url);
  };

  const downloadFilesHandler = async (): Promise<void> => {
    const { url, downloadFileName } = generateUrl();

    if (!url) {
      if (onRequestClose) {
        onRequestClose();
      }
      return;
    }

    try {
      const response = await fetch(url);

      if (response.status === 200) {
        const blob = await response.blob();
        downloadBlob(blob, downloadFileName);
        messageRef.current = 'Files downloaded.';
      } else if (response.status === 400) {
        messageRef.current = response.statusText;
      } else {
        messageRef.current = 'Error downloading files.';
        console.log('Error code');
      }
    } catch (error) {
      messageRef.current = 'Error downloading files.';
      console.error(error);
    } finally {
      if (openSnackBar) {
        openSnackBar(messageRef.current);
      }
      if (onRequestClose) {
        onRequestClose();
      }
    }
  };

  const showExplorerDialog = (filter: string = ''): void => {
    setExplorerDialogOpen(true);
    setFilterFiles(filter);
  };

  const closeExplorerDialog = (selectedNodes: any): void => {
    setExplorerDialogOpen(false);
    if (selectedNodes) {
      const paths = Object.values(selectedNodes).map((s: any) => s.path);
      setDownloadPaths(paths);
      setDownloadPathsDisplayText(
        paths
          .map((path) => path.split('/').pop())
          .join(' - '),
      );
    }
  };

  const changeDownloadFilePathsDisplayText = (text: string): void => {
    setDownloadPaths([text]);
    setDownloadPathsDisplayText(text);
  };

  let buttonLabel: string;
  let title: string;
  let content: React.ReactNode;
  let actionHandler: () => void;
  let isDisabled: boolean;

  if (mode === 'UPLOAD') {
    buttonLabel = 'Upload';
    title = 'Upload files';
    actionHandler = uploadFilesHandler;
    isDisabled = !uploadFiles;

    content = (
      <StyledRoot>
        <Box className="container">
          <input
            ref={fileInputRef}
            multiple
            type="file"
            className="input"
            onChange={onUploadFileArrayChange}
            style={{ width: '100%' }}
          />
        </Box>
        <Box mt={2}>{`Accept: ${ACCEPTED_EXTENSIONS}`}</Box>
      </StyledRoot>
    );
  } else {
    // DOWNLOAD mode
    buttonLabel = 'DOWNLOAD';
    title = 'Download files';
    actionHandler = downloadFilesHandler;
    isDisabled = downloadPaths.length === 0 || !downloadPathsDisplayText;

    content = (
      <TextField
        fullWidth
        variant="filled"
        value={downloadPathsDisplayText}
        onChange={(e) => changeDownloadFilePathsDisplayText(e.target.value)}
        label="Files:"
        helperText="Select files to download"
        InputProps={{
          startAdornment: (
            <InputAdornment position="start">
              <Tooltip title="File explorer" placement="top">
                <FolderIcon
                  onClick={() => showExplorerDialog()}
                  sx={{ cursor: 'pointer' }}
                />
              </Tooltip>
            </InputAdornment>
          ),
        }}
      />
    );
  }

  return (
    <>
      <Dialog
        fullWidth
        maxWidth="sm"
        open={open}
        onClose={onRequestClose}
        {...otherProps}
      >
        <DialogTitle>{title}</DialogTitle>
        <DialogContent>{content}</DialogContent>
        <DialogActions>
          <Button onClick={onRequestClose}>CANCEL</Button>
          <Button
            color="primary"
            id="appBarPerformActionButton"
            disabled={isDisabled}
            onClick={actionHandler}
          >
            {buttonLabel}
          </Button>
        </DialogActions>
      </Dialog>

      <FileBrowser
        open={explorerDialogOpen}
        exploreOnlyDirs={false}
        filterFiles={filterFiles}
        toggleMode
        onRequestClose={closeExplorerDialog}
      />
    </>
  );
};

export default UploadDownloadFilesDialog;

